package controllers;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import person.User;
import transaction.Transaction;


import contract.EmployeeContract;
import contract.EventContract;
import controllers.ManagerTask.TaskType;
import controllers.interfaces.DataController;

//import controllers.mockController.MockController;
import budget.Budget;
import budget.Request;
import budget.Service;

public class AsyncController implements Runnable {
	public AsyncController(DataController controller){
		tasksQueue= new LinkedBlockingQueue<ManagerTask>();
		this.controller=controller;
	}
	public void putTask(ManagerTask task){
		try {tasksQueue.put(task);} 
		catch (InterruptedException e) {e.printStackTrace();}
	}
	public void abortAll(TaskType type){
		for (ManagerTask task:this.tasksQueue){
			if(task.getTaskType()==type)task.abort();
		}
		if (currentTask.getTaskType()==type)currentTask.abort();
	}
	@Override
	public void run() {
		currentTask=null;
		while(true){
			try{
				currentTask=this.tasksQueue.poll(TIMEOUT, TimeUnit.MINUTES);
				if (currentTask!=null && !currentTask.hasAborted()){
					Log.print("Richiesta: "+currentTask.getTaskType().name());
					Object data=this.execTask(currentTask);
					if (!currentTask.hasAborted()){
						Log.print("\t(Completata)\n");
						currentTask.getDataListener().onData(currentTask.getTaskType(),data);
					}else Log.print("\t(Annullata)\n");
				}else {Log.println("Richiesta: "+currentTask.getTaskType().name()+"\t(saltata)");}
			}
			catch (Exception e) {
				try{
					Log.print("\t(Fallita)\n");
					Log.print(e);
					if (!currentTask.hasAborted()){
						currentTask.getDataListener().onError(currentTask.getTaskType(), this.getException(e));
					}
				}catch(NullPointerException npe){}
			}
		}
	}
	private Object execTask(ManagerTask taskToDo)throws Exception{
			LinkedList<Object> arguments = new LinkedList<Object>(taskToDo.getArguments());
			switch (taskToDo.getTaskType()){
			/*Sistema*/
			case SYSTEM_INSERT_SYS_USER:{controller.createSystemUser();return null;}
			case SYSTEM_SET_SYS_USER:{controller.setSystemUser((String)arguments.get(0), (String)arguments.get(1));return null;}
			/*Sessione*/
			case USER_LOGIN:{controller.login((String)arguments.get(0), (String)arguments.get(1));return null;}
			case USER_LOGOUT:{controller.logout();return null;}
			case USER_CURRENT:{return controller.getCurrentUser();}
			case USER_PERMISSIONS:{return controller.getPermissions();}
			case USER_REGISTER:{controller.registerUser((User)arguments.get(0), (String)arguments.get(1),(String) arguments.get(2));return null;}
			case USER_MODIFY_PASSWORD:{controller.modifyUserPassword((String)arguments.get(1));return null;}
			/*Richieste*/
			case REQUEST_GET_ALL:{return controller.getRequests((String)arguments.get(0));}
			case REQUEST_SEND:{controller.registerRequest((Request) arguments.get(0));return null;}
			case REQUEST_REMOVE:{controller.removeRequest((Request)arguments.get(0));return null;}
			case REQUEST_ACCEPT:{controller.acceptRequest((Request) arguments.get(0));return null;}
			case REQUEST_DENY:{controller.denyRequest((Request)arguments.get(0),(String)arguments.get(1));return null;}
			/*Preventivi*/
			case BUDGET_GET_ALL:{return controller.getBudgets((String)arguments.get(0));}
			case BUDGET_SEND:{controller.acceptBudget((Budget) arguments.get(0));return null;}
			case BUDGET_MODIFY:{controller.modifyBudget((Budget)arguments.get(0));return null;}
			case BUDGET_REMOVE:{controller.removeBudget((Budget)arguments.get(0));return null;}
			/*Servizi*/
			case SERVICE_REMOVE:{controller.removeService((Service) arguments.get(0));return null;}
			case SERVICE_GET_ALL:{ return controller.getServices();}
			case SERVICE_ADD:{controller.addService((Service) arguments.get(0));return null;}
			case SERVICE_MODIFY:{controller.modifyService((Service) arguments.get(0));return null;}
			/*contratti eventi*/
			case EVENT_CONTRACT_GET_ALL:{return controller.getEventContracts((String) arguments.get(0));}
			case EVENT_CONTRACT_SEND:{controller.acceptEventContract((EventContract)arguments.get(0));return null;}
			case EVENT_CONTRACT_REVERT_TO_BUDGET:{controller.revertEventContract((EventContract)arguments.get(0));return null;}
			/*contratti employee*/
			case EMPLOYEE_CONTRACT_GET_ALL:{return controller.getEmployeeContracts();}
			case EMPLOYEE_CONTRACT_REMOVE:{controller.firesEmployee((EmployeeContract)arguments.get(0));return null;}
			case EMPLOYEE_CONTRACT_SEND:{controller.acceptEmployeeContract((EmployeeContract)arguments.get(0));return null;}
			/*eventi*/
			case EVENT_GET_ALL:{return controller.getEvents((String)arguments.get(0));}
			/*transazioni*/
			case TRANSACTION_GET_ALL:{return controller.getTransactions();}
			case TRANSACTION_GET_STATS:{return controller.getAllStats();}
			case TRANSACTION_SEND:{controller.addTransaction((Transaction)arguments.get(0));return null;}
			case TRANSACTION_PAY_WAGES:{controller.payWages();return null;}
			case TRANSACTION_GET_WAGES_TRANSACTIONS:{return controller.getWagesTransactions();}
			default: {
				Log.printlnErr("Unknow: "+taskToDo.getTaskType().name());
				throw new Exception("UNKNOWN_TASK");}
		}
	}
	private Exception getException(Exception e){
		Exception retException=null;
		try{retException= new Exception(ExceptionsTypes.valueOf(e.getMessage()).name());}
		catch(Exception ex){
			try{
				retException=new Exception(FieldErrors.valueOf(e.getMessage()).name());
			}catch(Exception ex1){
				retException=new Exception(ExceptionsTypes.UNKNOW_ERROR.name()); 
			}
		}
		return retException;
	}
	private ManagerTask currentTask;
	private DataController controller;
	private LinkedBlockingQueue<ManagerTask> tasksQueue;
	private static final long TIMEOUT =30; 
}
